//---LICENSE
//	This file is part of the Haptik Library Source Distribution.
// Copyright (C) 2003-2006 by Maurizio de Pascale. All rights reserved.
//
// This library is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License("GPL") version 2
// as published by the Free Software Foundation.
//---------------------------------------------------------------------->

 
 
//---HEADER
//	Name:	Haptik Library
//	Desc:	Component Based Haptic Devices Access Library
//	Auto:	Maurizio de Pascale
//	Date:	July 17th 2005
//	Tabs:	tabbed at 3
//	Http:	www.haptiklibrary.org
//	Svns:	$Revision: 95 $
//			$Date: 2006-12-02 20:23:39 +0100 (sab, 02 dic 2006) $
//------------------------------------------------------------>
#include <RSLib/Common.hpp>
#ifndef RSLIB___HAPTIK_HPP
#define RSLIB___HAPTIK_HPP
 
 
 
//---INCLUDE
//--------------------->
#include <RSLib/Types.hpp>
#include <RSLib/LowLevel.hpp>
#include <RSLib/Math/3D.hpp>
 
 
 
//---DLL IMPORT EXPORT
//------------------------------>
#ifndef HAPTIK_DLL_IMPORT_EXPORT
	#define HAPTIK_DLL_IMPORT_EXPORT RSLIB___DLL_IMPORT
	
	#if defined(RSLIB___WINDOWS)
		#pragma comment(lib,"Haptik.Library.lib")
	#endif
#endif
 
 
 
//---SDK VERSION
//------------------------------->
#define HAPTIK_SDK_VERSION 0x0101
 
 
 
//---INTERFACE IDS
//----------------------------------------------->
#define HAPTIK_IHAPTIKLIBRARY				0x80008001
#define HAPTIK_IHAPTIKDEVICE				0x80008011
#define HAPTIK_IHAPTIKPLUGIN				0x80008031
 
 
 
//---MACRO
//------------------------------------------------------------------->
#define RELEASE_HAPTIK_INTERFACE(ptr) if(ptr){ptr->Release();ptr=NULL;}
 
 
 
//---FUNCTION
//	Desc: C-based entrypoint to retrieve IHaptikLibrary interfaces
//------------------------------------------------------------------------------------------------------------->
extern "C" HAPTIK_DLL_IMPORT_EXPORT RSLib::Pointer GetHaptikLibraryInterface(IN RSLib::Unsigned32 interfaceId = HAPTIK_IHAPTIKLIBRARY);
 
 
 
//---RETURN VALUES
//	Desc:	HRESULT-like return values.
//			Use the FAILED(ret) and SUCCEEDED(ret) macros
//---------------------------------------------------->
#define HAPTIK_SUCCESS						0x00000000
#define HAPTIK_WARNING						0x00000001
#define HAPTIK_ALREADY						0x00000001
#define HAPTIK_CALIBRATED					0x00000010
#define HAPTIK_NOTCALIBRATED				0x00000020
#define HAPTIK_ERROR							0x80000000
#define HAPTIK_FAILURE						0x80000000
#define HAPTIK_SDK_ERROR					0x80000001
#define HAPTIK_MEMORY_ERROR				0x80000002
#define HAPTIK_UNSUPPORTED					0x80000003
#define HAPTIK_OUT_OF_RANGE				0x80000004
#define HAPTIK_NO_SUCH_DEVICE				0x80000005
#define HAPTIK_NOT_INITIALIZED			0x80000006
 
 
 
 
//---DEVICE IDS
//----------------------------------------------->
#define HAPTIK_DEFAULT_DEVICE				0x80FFFFFF
#define HAPTIK_MOUSE_SPECTRE				0x80FF8001
#define HAPTIK_BETAMAX_PLAYER				0x80FF8002
#define HAPTIK_BETAMAX_RECORDER			0x80FF8003
#define HAPTIK_PHANTOM_PREMIUM			0x80FF4001
#define HAPTIK_PHANTOM_DESKTOP			0x80FF4002
#define HAPTIK_PHANTOM_OMNI				0x80FF4003
#define HAPTIK_PHANTOM_PREMIUM6D			0x80FF4004
#define HAPTIK_DELTA							0x80FFC001
#define HAPTIK_OMEGA							0x80FFC002
#define HAPTIK_FREEDOM6S					0x80FF2001
#define HAPTIK_CUBIC							0x80FF2002
#define HAPTIK_VIRTUOSE6D					0x80FF6001
#define HAPTIK_VIRTUOSE3D					0x80FF6002
 
 
 
 
namespace RSLib {
 
 
 
//---STRUCT
//	Desc:	Describe library implementation
//-------------------------------------->
typedef class HaptikLibraryInfo
{
public:
	const Char8* name;
	const Char8* company;
	const Char8* version;
	Unsigned32 versionNumbers[4];
	
private:
	Dword reserved[9];
}*HaptikLibraryInfoPtr;
 
 
 
//---STRUCT
//	Desc:	Describe a plugin
//---------------------------->
typedef class HaptikPluginInfo
{
public:
	const Char8* name;
	const Char8* company;
	const Char8* version;
	Unsigned32 versionNumbers[4];
	Unsigned32 numberOfDevices;
	
private:
	Dword reserved[8];
}*HaptikPluginInfoPtr;
 
 
 
//---STRUCT
//	Desc:	Describe an installed device
//------------------------------------>
typedef class HaptikDeviceInfo
{
public:
	Unsigned32 id;					//device unique id
	
public:
	const Char8* name;				//device name
	const Char8* model;				//device model
	const Char8* manufacturer;		//device manifacturer
	
public:
	Boolean ready;				//device ready
	
//	EXTENDED INFOS
public:
//	Rate
	Float32 currentRate;
	Float32 defaultRate;
	Float32 maxRate;
	Float32 minRate;

//	Workspace
	union	{ 
		struct{
			Float32 maxX;
			Float32 maxY;
			Float32 maxZ;
		};	
		struct{Math::Vector3<Float32> maxWorkspace;};
	};
	union	{
		struct{
			Float32 minX;
			Float32 minY;
			Float32 minZ;
		};
		struct{Math::Vector3<Float32> minWorkspace;};
	};
	
	
//	Force Feedback
	Float32 maxForceIntensity;
	Float32 maxTorqueIntensity;
	
//	Buttons
	Unsigned32 numberOfButtons;
	
//	Hardware Capabilities
	Unsigned32 capabilities;
	
private:
	Dword reserved[4];
}*HaptikDeviceInfoArray,*HaptikDeviceInfoPtr;
 
 
 
//---CAPABILITIES
//	Desc:	If corresponding bit is set in the capabilities mask
//			then the device supports this feature in hardware
//--------------------------------------------------------->
#define HAPTIK_CAPABILITY_POSITION				0x00000001
#define HAPTIK_CAPABILITY_VELOCITY				0x00000002
#define HAPTIK_CAPABILITY_ORIENTATION			0x00000004
#define HAPTIK_CAPABILITY_FORCEFEEDBACK		0x00000010
#define HAPTIK_CAPABILITY_TORQUEFEEDBACK		0x00000020
#define HAPTIK_CAPABILITY_VARIABLE_RATE		0x00000100
 
 
 
//---STRUCT
//	Desc:	Data exchanged with an IHaptikDevice 
//	Note:	This is only a template. You can define another struct 
//			using your classes for matrix/vector computations.
//			Memory layout and order should be preserved.
//			adding of "operator HaptikData&()" allows for unchanged syntax
//--------------------------------------------------------------------->
typedef class HaptikData
{
public:
//	Output from Device
	float4x4 matrix;
	float3 position;
	float3 velocity;
	Unsigned32 buttonMask;
	
private:
	Dword reserved0[1];
	
public:
//	Input to Device
	float3 forceFeedback;
	float3 torqueFeedback;
	
private:
	Dword reserved1[2];
	
public:
//	Helper Methods
	Boolean Button(Unsigned32 index = 0)	{return (buttonMask & (1<<index)) == 1;}
	
public:
	HaptikData()	{ZeroMemory(this,sizeof(*this));}
}*HaptikDataPtr;
 
 
 
//---STRUCT
//	Desc:	User Data exchanged with an IHaptikDevice
//	Note:	Applications can also ignore this data.
//---------------------------------------------->
typedef class HaptikUserData
{
public:
	Dword userData;
	Unsigned32 lastError;
	
//	Make struct 32 bytes aligned and reserve space for extensions
private:
	Dword reserved[6];
	
public:
	HaptikUserData()	{userData = 0;	lastError = HAPTIK_SUCCESS;}
}*HaptikUserDataPtr;
 
 
 
//---INTERFACE
//	Desc:	Interface exposed by the library component
//------------------------------------------------->
typedef class IHaptikLibrary
{
public:
	virtual Unsigned32 Init(IN Pointer reserved = NULL) PURE;
	virtual Unsigned32 Release() PURE;
		
	virtual Unsigned32 GetNumberOfDevices() PURE;
	virtual Unsigned32 GetDeviceInfo(IN Unsigned32 deviceId, OUT HaptikDeviceInfo& info) PURE;
	virtual Pointer GetDeviceInterface(IN Unsigned32 deviceId = HAPTIK_DEFAULT_DEVICE, IN Unsigned32 interfaceId = HAPTIK_IHAPTIKDEVICE) PURE;
	
//	All methods below are reserved for future uses and will currently return HAPTIK_UNSUPPORTED
	virtual Unsigned32 GetNumberOfPlugins() PURE;
	virtual Unsigned32 GetPluginInfo(IN Unsigned32 pluginId, OUT HaptikPluginInfo& info) PURE;
	virtual Pointer GetPluginInterface(IN Unsigned32 pluginId, IN Unsigned32 interfaceId = HAPTIK_IHAPTIKPLUGIN) PURE;
	
	virtual Unsigned32 GetLibraryInfo(OUT HaptikLibraryInfo& info) PURE;
}*IHaptikLibraryInterface;
 
 
 
//---INTERFACE
//	Desc:	Represent a 6DOF haptic device
//------------------------------------->
typedef class IHaptikDevice
{
public:
	virtual Unsigned32 Init(IN Pointer method = NULL, IN Pointer object = NULL) PURE;
	virtual Unsigned32 Release() PURE;
	
//	Control	
	virtual Unsigned32 Start() PURE;
	virtual Unsigned32 Stop() PURE;

//	Access
	virtual Unsigned32 Read(OUT HaptikData& data) PURE;
	virtual Unsigned32 Write(IN HaptikData& data) PURE;
	
//	Info & Configuration
	virtual Unsigned32 SetRate(IN Float32 rateInHz) PURE;
	virtual Float32 GetRate() PURE;
	virtual Unsigned32 GetInfo(OUT HaptikDeviceInfo& info) PURE;
	virtual Unsigned32 SetUserData(IN Dword userData) PURE;
	virtual Dword GetUserData() PURE;
	virtual Unsigned32 SetCallback(IN Pointer method = NULL, Pointer object = NULL, IN Dword reserved = NULL) PURE;
	virtual Unsigned32 GetCallback(OUT Pointer& method, OUT Pointer& object = NULL_REFERENCE(Pointer), IN Dword reserved = NULL) PURE;
	virtual Unsigned32 GetLastError() PURE;
	
//	Recalibration
	virtual Unsigned32 GetCalibrationStatus() PURE;
	virtual Unsigned32 Recalibrate(IN Unsigned32 reserved = NULL) PURE;
}*IHaptikDeviceInterface;
 
 
 
//---TYPEDEF
//	Desc:	Prototype for callbacks
//-------------------------------------------->
typedef Void (*HaptikCallbackPtr)(IN OUT HaptikData&);
typedef Void (*HaptikCallbackExPtr)(IN OUT HaptikData&, IN OUT HaptikUserData&);
 
 
 
//---CLASS
//	Name:	Haptik
//	Desc:	C++ Wrapper Class around the IHaptikLibrary interface
//------------------------------------------------------------>
class Haptik
{
public:
	Unsigned32 numberOfDevices;
	HaptikDeviceInfoArray device;
	IHaptikLibraryInterface library;
	
public:
	Haptik() : device(NULL), numberOfDevices(0)
	{
		library = (IHaptikLibraryInterface)GetHaptikLibraryInterface();
		if (library)
		{
		//!TODO:	assert SDK version <= LIB version
			
			library->Init(NULL);
			RefreshDeviceList();
		}
	}
	~Haptik()
	{
		if (library)	library->Release();
		if (device)		delete[]device;
	}
	
public:
	Pointer GetDeviceInterface(IN Unsigned32 deviceId = HAPTIK_DEFAULT_DEVICE, IN Unsigned32 interfaceId = HAPTIK_IHAPTIKDEVICE)
	{
		if (library)
		{
			Pointer interfacePtr = library->GetDeviceInterface(deviceId,interfaceId);
			RefreshDeviceList();
			return interfacePtr;
		}
		else return NULL;
	}
	Unsigned32 RefreshDeviceList()
	{
		if (library)
		{
			if (device)	delete[] device;
			numberOfDevices = library->GetNumberOfDevices();
			device = new HaptikDeviceInfo[numberOfDevices];
			for(Unsigned32 i=0 ; i<numberOfDevices ; i++)	library->GetDeviceInfo(i,device[i]);
			return HAPTIK_SUCCESS;
		}
		else return HAPTIK_UNSUPPORTED;
	}
	
public:
	IHaptikDeviceInterface GetHaptikDeviceInterface(IN Unsigned32 deviceId = HAPTIK_DEFAULT_DEVICE)
	{
		return (IHaptikDeviceInterface)GetDeviceInterface(deviceId,HAPTIK_IHAPTIKDEVICE);
	}
	
public:
	static const Char8* ResultToString(Unsigned32 result)
	{
		switch(result)
		{
			case HAPTIK_SUCCESS:
			return "Operation Completed Successfully";
			
			case HAPTIK_WARNING:
			return "Warning";
			
			case HAPTIK_ERROR:
			return "Generic Error";
			
			case HAPTIK_SDK_ERROR:
			return "An error has been reported from a device SDK";
			
			case HAPTIK_MEMORY_ERROR:
			return "A Memory Allocation Failed";
			
			case HAPTIK_UNSUPPORTED:
			return "Operation/Interface not Supported";
			
			case HAPTIK_OUT_OF_RANGE:
			return "Request is out of range";
			
			case HAPTIK_NO_SUCH_DEVICE:
			return "No such Device";
			
			case HAPTIK_NOT_INITIALIZED:
			return "Interface has not been initialized";
			
			default:
			return "Unknown Return Value";
		}
	}
	
public:
	template <typename T = IHaptikDevice> class Interface
	{
	protected:
		T* ptr;
		
	public:
		Interface() : ptr(NULL){}
		Interface(T* const ptr_): ptr(ptr_){}
		~Interface() {if(ptr) ptr->Release();}
		
	public:
		bool operator != (T* ptr_) {return ptr != ptr_;}
		bool operator == (T* ptr_) {return ptr == ptr_;}
		T* operator=(T* ptr_) {if(ptr) ptr->Release(); return ptr = ptr_;}
		T* operator->() {return ptr;}
		
	private:
		Interface(const Interface&);
	};
};
 
 
 
}//namespace RSLib
 
 
 
#endif//RSLIB___HAPTIK_HPP
